/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			ETSheetView.cc
  \date			september 2011
  \author		TNick

  \brief		Contains the implementation for ETSheetView class


  Copyright (c) 2011, Nicu Tofan
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
 * Neither the name of the copyright holder nor the
   names of its contributors may be used to endorse or promote products
   derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL NICU TOFAN BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<main.h>

#include	<math.h>

#include	<QGLWidget>
#include	<QSplitter>
#include    <QMessageBox>
#include    <QObjectList>

#include	<sheet/ETI_CplxTxt.h>
#include	<sheet/ETSubItem.h>
#include	<sheet/ETVpCommand.h>
#include	<sheet/ETSheet.h>

#include	<sheet/vp_cmd/ETVpCmd_EditSubI.h>
#include	<gui/mainwindow.h>
#include	<gui/mdichild.h>

#include	"ETSheetView.h"

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */
DDHC_CONTENT(ETSheetView)

/* ------------------------------------------------------------------------- */
void		ETSheetView::init		( void )
{
	//setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
	setInteractive(true);
	//setForegroundBrush(QBrush(Qt::yellow));
	//setBackgroundBrush(QBrush(Qt::darkCyan));
	setDragMode(QGraphicsView::RubberBandDrag); /* QGraphicsView::ScrollHandDrag */
	setCacheMode(QGraphicsView::CacheBackground);
	setViewport(new QGLWidget);
	setAlignment(Qt::AlignLeft | Qt::AlignTop);
	setMouseTracking(true);
	centerOn(0, 0);

	/* no items being edited right now */
	temp_editor = NULL;
	crt_sub_itm = NULL;
	crt_itm = NULL;
	running_command = NULL;
	rot_ang_to_s = 0;
	scale_to_s = 1;
	trans_x = 0.0;
	trans_y = 0.0;

	//setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
	DDHC_CONSTRUCT;
	DDHC_VARIABLE(temp_editor);
	DDHC_VARIABLE(crt_itm);
	DDHC_VARIABLE(crt_sub_itm);
	DDHC_VARIABLE(running_command);
	DDHC_VARIABLE(b_sel_left);
	DDHC_VARIABLE(rot_ang_to_s);
	DDHC_VARIABLE(scale_to_s);
	DDHC_VARIABLE(trans_x);
	DDHC_VARIABLE(trans_y);

//    DDHC_NODE(&cl_inst);

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETSheetView::ETSheetView	(ETSheet * the_scene, QWidget *parent)
	: QGraphicsView (parent)
{
	init();
	setScene(the_scene);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETSheetView::~ETSheetView	( void )
{
	ETSheet * sht = static_cast<ETSheet * >(scene());
	if (sht != NULL)
	{
		if (sht->currentVP() == this)
		{
			sht->setCurrentVp(NULL);
		}
	}
	DDHC_DESTRUCT
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void        ETSheetView::setEditor				( QWidget * new_editor )
{
	if (temp_editor != NULL)
	{
		temp_editor->close();
		temp_editor->deleteLater();
	}
	temp_editor = new_editor;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::closeEditor			( void )
{
	if (temp_editor != NULL)
	{
		if (crt_sub_itm != NULL)
		{
			/// @todo call save function
		}
		temp_editor->close();
		temp_editor->deleteLater();
		temp_editor = NULL;
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::setCurrentSubI			(
		ETI_CplxTxt * new_i, ETSubItem * new_si)
{
	if (crt_sub_itm != NULL)
	{
		crt_sub_itm->deselect(NULL, false);
	}

	if (new_si == NULL)
	{
		crt_sub_itm = NULL;
		crt_itm = NULL;
	}
	else
	{
		if (new_i == NULL)
			new_i = new_si->fatherCplx();

		crt_itm = new_i;
		crt_sub_itm = new_si;
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::makeCurrentSubI		(
		ETI_CplxTxt * new_i, ETSubItem * new_si)
{
	if (new_i == NULL)
		new_i = new_si->fatherCplx();

	setCurrentSubI(new_i, new_si);

	new_i->update();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::makeSubIVisible		(ETSubItem * trg_si)
{
	Q_UNUSED(trg_si);
	/// @todo see \ref various "Various" section
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::makeIVisible			(ETI_CplxTxt * trg_i)
{
	Q_UNUSED(trg_i);
	/// @todo see \ref various "Various" section
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::startCommand			(ETVpCommand * new_cmd)
{
	/* cancel running command, if any */
	if (inCommand())
	{
		cancelCommand();
	}

	/* save a pointer to this new command */
	running_command = new_cmd;

	/* and inform it that it has started */
	if (new_cmd != NULL)
	{
		if (running_command->start(this) == false)
		{
			delete running_command;
			running_command = false;
		}
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::cancelCommand			( void )
{
	/* cancel running command, if any */
	if (inCommand())
	{
		running_command->cancel(this);
		delete running_command;
		running_command = NULL;
	}
	else
	{
		qDebug("ETSheetView recieved cancel command while no command was running");
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::acceptCommand			( void )
{
	/* cancel running command, if any */
	if (inCommand())
	{
		running_command->accepted(this);
		cancelCommand();
	}
	else
	{
		qDebug("ETSheetView recieved accept command while no command was running");
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::contextMenuEvent		( QContextMenuEvent * event )
{
	if (inCommand())
	{
		if (!running_command->context(this, event))
			return;
	}
	QGraphicsView::contextMenuEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::dragEnterEvent			( QDragEnterEvent * event )
{
	if (inCommand())
	{
		if (!running_command->dragEnter(this, event))
			return;
	}
	QGraphicsView::dragEnterEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::dragLeaveEvent			( QDragLeaveEvent * event )
{
	if (inCommand())
	{
		if (!running_command->dragLeave(this, event))
			return;
	}
	QGraphicsView::dragLeaveEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::dragMoveEvent			( QDragMoveEvent * event )
{
	if (inCommand())
	{
		if (!running_command->dragMove(this, event))
			return;
	}
	QGraphicsView::dragMoveEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::dropEvent				( QDropEvent * event )
{
	if (inCommand())
	{
		if (!running_command->drop(this, event))
			return;
	}
	QGraphicsView::dropEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::keyPressEvent			( QKeyEvent * event )
{
	/// \callgraph

	if (inCommand())
	{
		if (!running_command->keyPress(this, event))
			return;
	}

	ETSheet * sh = static_cast<ETSheet *>(scene());

	switch (event->key())		{
	case	Qt::Key_Escape:	{
		sh->clearSelection();
		sh->update();
		break; }
	case	Qt::Key_Tab:	{
		break; }
	case	Qt::Key_Backtab:{
		break; }
	case	Qt::Key_Backspace:	{
		if (crt_sub_itm != NULL)
		{
			if (selIsLeft())
			{
				crt_sub_itm->navKey(this, Qt::Key_Left);
				setSelRight();
			}

			if (crt_sub_itm->isSelected())
			{
				crt_sub_itm->remove();
				crt_itm->update();
			}
			else
			{
				crt_sub_itm->select();
			}
		}
		break; }
	case	Qt::Key_Return:	{
		ETVpCmd_EditSubI * sic = new ETVpCmd_EditSubI();
		startCommand(sic);
		break; }
	case	Qt::Key_Delete:	{
		if (crt_sub_itm != NULL)
		{
			if (!selIsLeft())
			{
				crt_sub_itm->navKey(this, Qt::Key_Right);
				setSelLeft();
			}

			if (crt_sub_itm->isSelected())
			{
				crt_sub_itm->remove();
				crt_itm->update();
			}
			else
			{
				crt_sub_itm->select();
			}
		}
		break; }
	case	Qt::Key_Left:
	case	Qt::Key_Up:
	case	Qt::Key_Right:
	case	Qt::Key_Down:	{
		if (crt_sub_itm != NULL)
		{
			crt_sub_itm->navKey(this, (Qt::Key)event->key());
		}
		else
		{
			/// @todo select one from current view
		}
		break; }
	default:				{
		QGraphicsView::keyPressEvent(event);
		return; }
	}
	event->accept();

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::keyReleaseEvent		( QKeyEvent * event )
{
	if (inCommand())
	{
		if (!running_command->keyRelease(this, event))
			return;
	}
	QGraphicsView::keyReleaseEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::mouseDoubleClickEvent	( QMouseEvent * event )
{
	if (inCommand())
	{
		if (!running_command->mouseDoubleClick(this, event))
			return;
	}
	QGraphicsView::mouseDoubleClickEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::mouseMoveEvent			( QMouseEvent * event )
{

	g_MW->c_sheet.showXY(mapToScene(event->pos()));

	if (inCommand())
	{
		if (!running_command->mouseMove(this, event))
			return;
	}
	QGraphicsView::mouseMoveEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::mousePressEvent		( QMouseEvent * event )
{
	ETSheet * sht = static_cast<ETSheet *>(scene());
	if (sht->currentVP() != this)
	{
		sht->setCurrentVp(this);
		event->accept();
		return;
	}

	if (inCommand())
	{
		if (!running_command->mousePress(this, event))
			return;
	}
	QGraphicsView::mousePressEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::mouseReleaseEvent		( QMouseEvent * event )
{
	if (inCommand())
	{
		if (!running_command->mouseRelease(this, event))
			return;
	}
	QGraphicsView::mouseReleaseEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::wheelEvent				( QWheelEvent * event )
{
	if (inCommand())
	{
		if (!running_command->wheel(this, event))
			return;
	}
	if (event->orientation() == Qt::Vertical)
	{
		/* default zoom scrolls the area */
		if ((event->modifiers() & Qt::ControlModifier) != 0)
		{ /* with ctrl hel down, we zoom */
			qreal fact;
			if (event->delta() > 0)
			{
				fact = 1 + (
							((qreal)event->delta() *
							 400) /
							100000
							);
				zoomIn(fact);
			}
			else
			{
				fact = 1 + (
							(-1) *
							(((qreal)event->delta() *
							  400) /
							 100000)
							);
				zoomOut(fact);
			}
			event->accept();
			return;
		}
	}
	QGraphicsView::wheelEvent(event);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::navLeaveLeft			(ETI_CplxTxt * it_base)
{
	Q_UNUSED(it_base);

	/// @todo implement navigation

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::navLeaveRight			(ETI_CplxTxt * it_base)
{
	Q_UNUSED(it_base);

	/// @todo implement navigation

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::navLeaveTop			(ETI_CplxTxt * it_base)
{
	Q_UNUSED(it_base);

	/// @todo implement navigation

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::navLeaveBtm			(ETI_CplxTxt * it_base)
{
	Q_UNUSED(it_base);

	/// @todo implement navigation

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void		ETSheetView::drawBackground			(
		QPainter * painter, const QRectF & rect )
{
	/* clear the background */
	ETSheet * sht = static_cast<ETSheet * >(scene());

	if (this == sht->currentVP())
		painter->fillRect(rect, backgroundBrush());
	else
	{
		/// @todo read the color to be used from settings
		painter->fillRect(rect, Qt::darkGray);
	}


	//	/// @todo settings to enable / disable grid

//		qreal cross_side = 5 / getScale();
//		qreal cross_side2 = 4 / getScale();
//		qreal span = 0.0000001;
//		while (rect.width() / span > 20)
//		{
//			span *= 10;
//		}

//		qreal x_start = (floor(rect.x() / span) ) * span;
//		qreal y_start = (floor(rect.y() / span) ) * span;

//		/* loop horizontally, starting from left to right */
//		qreal x_crt = x_start;
//		qreal y_crt;
//		while (x_crt < rect.right())
//		{
//			/* loop vertically, starting from top to bottom*/
//			y_crt = y_start;
//			while (y_crt < rect.bottom())
//			{
//				painter->drawLine(
//							x_crt - cross_side,
//							y_crt,
//							x_crt + cross_side2,
//							y_crt
//							);

//				painter->drawLine(
//							x_crt,
//							y_crt - cross_side,
//							x_crt,
//							y_crt + cross_side2
//							);

//				y_crt += span;
//			}

//			x_crt += span;
//		}


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::loadXML				(
		ETSheet * dest, QWidget * parent, QDomElement dom_e )
{
	QDomElement li_it;

	li_it = dom_e.firstChildElement(XML_TAG_VP_SPLIT);
	if (li_it.isNull())
	{ /* one viewport expected */
		li_it = dom_e.firstChildElement(XML_TAG_VP);
		if (li_it.isNull())
		{ /* no viewport. wrong input. create default one */
			qDebug() << "No viewport information specified";
			ETSheetView * vp_crt = new ETSheetView(dest, dest->assocMDI());
			dest->assocMDI()->setWidget(vp_crt);
			dest->setCurrentVp(vp_crt);
		}
		else
		{ /* create the one and only viewport */
			loadXMLViewport(dest, parent, li_it);
		}
	}
	else
	{ /* we're in the split game */
		loadXMLVpSplit(dest, parent, li_it);
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETSheetView *	ETSheetView::loadXMLViewport		(
		ETSheet * dest, QWidget * parent, QDomElement dom_e )
{

	ETSheetView * new_vp = new ETSheetView(dest, parent);
	QDomElement li_it;
	QDomElement li_it2;
	bool		b_ok;
	qreal		r_x = 0.0;
	qreal		r_y = 0.0;



	if (parent == dest->assocMDI())
	{ /* the top level */
		dest->assocMDI()->setWidget(new_vp);
	}
	else
	{
		QSplitter * spl = static_cast<QSplitter *>(parent);
		spl->addWidget(new_vp);
	}
	new_vp->setScene(dest);
	new_vp->show();


	/* the position whitin viewport */
	li_it = dom_e.firstChildElement(XML_TAG_TRANSL);
	if (!li_it.isNull())
	{
		for (;;)
		{
			li_it2 = li_it.firstChildElement(XML_TAG_X);
			if (!li_it2.isNull())
			{
				r_x = li_it2.text().toDouble(&b_ok);
				if (!b_ok)
				{
					qDebug() << "The position could not be understood: <"
							 << li_it2.text() << ">";
					break;
				}

				if (!li_it2.nextSiblingElement(XML_TAG_X).isNull())
				{
					qDebug() << "The input presented more than one "
							 << XML_TAG_X << " tags, when only "
							 << "one per viewport element is allowed";
				}
			}
			li_it2 = li_it.firstChildElement(XML_TAG_Y);
			if (!li_it2.isNull())
			{
				r_y = li_it2.text().toDouble(&b_ok);
				if (!b_ok)
				{
					r_x = 0.0;
					qDebug() << "The position could not be understood: <"
							 << li_it2.text() << ">";
					break;
				}
				if (!li_it2.nextSiblingElement(XML_TAG_Y).isNull())
				{
					qDebug() << "The input presented more than one "
							 << XML_TAG_Y << " tags, when only "
							 << "one per viewport element is allowed";
				}
			}
			break;
		}
		new_vp->translate(-r_x, -r_y);

		if (!li_it.nextSiblingElement(XML_TAG_TRANSL).isNull())
		{
			qDebug() << "The input presented more than one "
					 << XML_TAG_TRANSL << " tags, when only "
					 << "one per viewport element is allowed";
		}
	}

	/* the rotation */
	li_it = dom_e.firstChildElement(XML_TAG_ROT);
	if (!li_it.isNull())
	{
		r_x = li_it.text().toDouble(&b_ok);
		if (!b_ok)
		{
			r_x = 0.0;
			qDebug() << "The rotation could not be understood: <"
					 << li_it.text() << ">";
		}
		else
		{
			new_vp->rotate(r_x);
		}

		if (!li_it.nextSiblingElement(XML_TAG_ROT).isNull())
		{
			qDebug() << "The input presented more than one "
					 << XML_TAG_ROT << " tags, when only "
					 << "one per viewport element is allowed";
		}

	}

	/* the scale */
	li_it = dom_e.firstChildElement(XML_TAG_SCALE);
	if (!li_it.isNull())
	{
		r_x = li_it.text().toDouble(&b_ok);
		if (!b_ok)
		{
			r_x = 0.0;
			qDebug() << "The scale could not be understood: <"
					 << li_it.text() << ">";
		}
		else
		{
			new_vp->scale(r_x, r_x);
		}

		if (!li_it.nextSiblingElement(XML_TAG_ROT).isNull())
		{
			qDebug() << "The input presented more than one "
					 << XML_TAG_SCALE << " tags, when only "
					 << "one per viewport element is allowed";
		}
	}

	/* is this the active one? */
	li_it = dom_e.firstChildElement(XML_TAG_ACTIVE);
	if (!li_it.isNull())
	{

		dest->setCurrentVp(new_vp);

		if (!li_it.nextSiblingElement(XML_TAG_ACTIVE).isNull())
		{
			qDebug() << "The input presented more than one "
					 << XML_TAG_ACTIVE << " tags, when only "
					 << "one per viewport element is allowed";
		}

	}


	return new_vp;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void *			ETSheetView::loadXMLVpSplit		(
		ETSheet * dest, QWidget * parent, QDomElement dom_e )
{

	QDomElement li_it;
	QSplitter * spl_new = new QSplitter(parent);
	if (parent == dest->assocMDI())
	{ /* the top level */
		dest->assocMDI()->setWidget(spl_new);
	}
	else
	{
		QSplitter * spl = static_cast<QSplitter *>(parent);
		spl->addWidget(spl_new);
	}

	/* orientation */
	li_it = dom_e.firstChildElement(XML_TAG_ORIENT);
	if (!li_it.isNull())
	{
		if (li_it.text() == XML_O_HORIZ)
		{
			spl_new->setOrientation(Qt::Horizontal);
		}
		else if (li_it.text() == XML_O_VERT)
		{
			spl_new->setOrientation(Qt::Vertical);
		}
		else
		{
			qDebug() << "Unknown orientation found for splitter: <"
					 << li_it.text() << ">";
		}
	}


	/* components */
	li_it = dom_e.firstChildElement(XML_TAG_VP_SPLIT);
	if (li_it.isNull())
	{ /* viewports expected */

		li_it = dom_e.firstChildElement(XML_TAG_VP);
		if (li_it.isNull())
		{/* nothing found */
			qDebug() << "Split element with no components found";
			return spl_new;
		}

		loadXMLViewport(dest, spl_new, li_it);

		li_it = li_it.nextSiblingElement(XML_TAG_VP);
		if (li_it.isNull())
		{ /* nothing found */
			qDebug() << "Degenerate split element with only one component found";
			return spl_new;
		}

		loadXMLViewport(dest, spl_new, li_it);

	}
	else
	{ /* one split found */

		loadXMLVpSplit(dest, spl_new, li_it);

		li_it = li_it.nextSiblingElement(XML_TAG_VP_SPLIT);
		if (li_it.isNull())
		{/* viewport expected */

			li_it = dom_e.firstChildElement(XML_TAG_VP);
			if (li_it.isNull())
			{/* nothing found */
				qDebug() << "Degenerate split element with only one component found";
				return spl_new;
			}

			loadXMLViewport(dest, spl_new, li_it);

		}
		else
		{/* second split found */
			loadXMLVpSplit(dest, spl_new, li_it);
		}
	}


	/* splitter data */
	li_it = dom_e.firstChildElement(XML_TAG_SPL_DATA);
	if (!li_it.isNull())
	{
		spl_new->restoreState(QByteArray::fromHex(li_it.text().toAscii()));
	}


	return spl_new;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::saveXML			(
		ETSheet * dest, QDomElement dom_e)
{

	/* get associated gui object */
	MdiChild * mdi_s = dest->assocMDI();
	if (mdi_s == NULL)
	{
		/* this sheet is only loaded but not shown */
		return;
	}


	/* get the top element (viewport / splitter */
	bool b_top_is_vp;
	QWidget * top_it = dest->vp_TopWidget(&b_top_is_vp);
	if (top_it == NULL)
	{
		/* failure of the code */
		qDebug() << " The saving of the viewports failed because "
				 << "top level widget could not be retrieved.";
		return;
	}


	/* see if this is an entire tree or just a single item */
	if (b_top_is_vp)
	{ /* just a viewport */
		QDomElement dom_it = dom_e.ownerDocument()
				.createElement(XML_TAG_VP);
		dom_e.appendChild(dom_it);

		ETSheetView * vp = static_cast<ETSheetView *>(top_it);
		vp->saveXMLViewport(dest, dom_it);
	}
	else
	{ /* a tree; provided element is a splitter */
		QDomElement dom_it = dom_e.ownerDocument()
				.createElement(XML_TAG_VP_SPLIT);
		dom_e.appendChild(dom_it);

		QSplitter * spl = static_cast<QSplitter *>(top_it);
		saveXMLVpSplit(dest, spl, dom_it);
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::saveXMLViewport		(
		ETSheet * dest, QDomElement dom_e ) const
{
	Q_UNUSED(dest);

	QDomElement dom_it;
	QDomElement dom_sit;
	QDomText	dom_tx;
	QTransform	vp_t = viewportTransform();


	/* save the translation */
	dom_it = dom_e.ownerDocument()
			.createElement(XML_TAG_TRANSL);
	dom_e.appendChild(dom_it);
	/*    X */
	dom_sit = dom_e.ownerDocument()
			.createElement(XML_TAG_X);
	dom_it.appendChild(dom_sit);
	dom_tx = dom_e.ownerDocument()
			.createTextNode(QString("%1").arg(vp_t.dx()));
	dom_sit.appendChild(dom_tx);
	/*    Y */
	dom_sit = dom_e.ownerDocument()
			.createElement(XML_TAG_Y);
	dom_it.appendChild(dom_sit);
	dom_tx = dom_e.ownerDocument()
			.createTextNode(QString("%1").arg(vp_t.dy()));
	dom_sit.appendChild(dom_tx);


	/* save the rotation */
	dom_it = dom_e.ownerDocument()
			.createElement(XML_TAG_ROT);
	dom_e.appendChild(dom_it);
	dom_tx = dom_e.ownerDocument()
			.createTextNode(QString("%1").arg(rot_ang_to_s));
	dom_it.appendChild(dom_tx);


	/* save the scale */
	dom_it = dom_e.ownerDocument()
			.createElement(XML_TAG_SCALE);
	dom_e.appendChild(dom_it);
	dom_tx = dom_e.ownerDocument()
			.createTextNode(QString("%1").arg(scale_to_s));
	dom_it.appendChild(dom_tx);


	/* if it's the active one, mark it as such */
	if (dest->currentVP() == this)
	{
		dom_it = dom_e.ownerDocument()
				.createElement(XML_TAG_ACTIVE);
		dom_e.appendChild(dom_it);
	}


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::saveXMLVpSplit			(
		ETSheet * dest, const QSplitter * spl, QDomElement dom_e )
{
	QDomElement	dom_it;
	QDomText	dom_tx;

	/* save the orientation */
	dom_it = dom_e.ownerDocument()
			.createElement(XML_TAG_ORIENT);
	dom_e.appendChild(dom_it);
	if (spl->orientation() == Qt::Horizontal)
	{
		dom_tx = dom_e.ownerDocument()
				.createTextNode(XML_O_HORIZ);
	}
	else
	{
		dom_tx = dom_e.ownerDocument()
				.createTextNode(XML_O_VERT);
	}
	dom_it.appendChild(dom_tx);


	/* splitter data */
	dom_it = dom_e.ownerDocument()
			.createElement(XML_TAG_SPL_DATA);
	dom_e.appendChild(dom_it);

	dom_tx = dom_e.ownerDocument()
			.createTextNode(spl->saveState().toHex());

	dom_it.appendChild(dom_tx);




	/* get the data about the components of this split */
	SplitData	spl_d;
	vp_SplitKids(spl, &spl_d);

	/* if there's no first, there are none */
	if (spl_d.first.comp.vp == NULL)
		return;


//	if (spl->orientation() == Qt::Horizontal)
//	{

//		/* save first */
//		if (spl_d.first.b_is_vp)
//		{
//			dom_it = dom_e.ownerDocument()
//					.createElement(XML_TAG_VP);
//			dom_e.appendChild(dom_it);
//			spl_d.first.comp.vp->saveXMLViewport(dest, dom_it);
//		}
//		else
//		{
//			dom_it = dom_e.ownerDocument()
//					.createElement(XML_TAG_VP_SPLIT);
//			dom_e.appendChild(dom_it);
//			saveXMLVpSplit(dest,spl_d.first.comp.split, dom_it);
//		}

//		/* save second */
//		if (spl_d.sec.b_is_vp)
//		{
//			dom_it = dom_e.ownerDocument()
//					.createElement(XML_TAG_VP);
//			dom_e.appendChild(dom_it);
//			spl_d.sec.comp.vp->saveXMLViewport(dest, dom_it);
//		}
//		else
//		{
//			dom_it = dom_e.ownerDocument()
//					.createElement(XML_TAG_VP_SPLIT);
//			dom_e.appendChild(dom_it);
//			saveXMLVpSplit(dest,spl_d.sec.comp.split, dom_it);
//		}

//	}
//	else
//	{

		/* save second */
		if (spl_d.sec.b_is_vp)
		{
			dom_it = dom_e.ownerDocument()
					.createElement(XML_TAG_VP);
			dom_e.appendChild(dom_it);
			spl_d.sec.comp.vp->saveXMLViewport(dest, dom_it);
		}
		else
		{
			dom_it = dom_e.ownerDocument()
					.createElement(XML_TAG_VP_SPLIT);
			dom_e.appendChild(dom_it);
			saveXMLVpSplit(dest,spl_d.sec.comp.split, dom_it);
		}

		/* save first */
		if (spl_d.first.b_is_vp)
		{
			dom_it = dom_e.ownerDocument()
					.createElement(XML_TAG_VP);
			dom_e.appendChild(dom_it);
			spl_d.first.comp.vp->saveXMLViewport(dest, dom_it);
		}
		else
		{
			dom_it = dom_e.ownerDocument()
					.createElement(XML_TAG_VP_SPLIT);
			dom_e.appendChild(dom_it);
			saveXMLVpSplit(dest,spl_d.first.comp.split, dom_it);
		}

//	}
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void				ETSheetView::ivp_SplitTopL      (
		ETSheetView * vp_loc, MdiChild * parent, Qt::Orientation orient)
{
	/* it is assumed that current tree only contains one item (there is one
   viewport in the MDI and that viewport is pointed by vp_loc */

	/* have a new splitter of proper orientation */
	QSplitter *  new_spl = new QSplitter(parent);
	new_spl->setOrientation(orient);

	/* reparent the existing viewport */
	vp_loc->setParent(new_spl);
	parent->setWidget(new_spl);
	new_spl->addWidget(vp_loc);
	vp_loc->show();

	/* create a clone of this viewport */
	ETSheetView * duplic = new ETSheetView(
				static_cast<ETSheet *>(vp_loc->scene()),
				new_spl);
	duplic->show();
	duplic->setTransform(vp_loc->transform());

	/* let the two viewports use equal ammounts of space */
	QList<int> sz_l;
	sz_l.append(1);
	sz_l.append(1);
	new_spl->setSizes(sz_l);

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETSheetView::ivp_SplitSplKid    (
		ETSheetView * vp_loc, QWidget * parent, Qt::Orientation orient)
{

	/* it is assumed that current tree contains more than one item (there is
   at least one split in the MDI */

	/* preserve aspect ratio across opperation for original splitter */
	QSplitter *  old_spl = static_cast<QSplitter *>(parent);
	QList<int> sz_l = old_spl->sizes();

	/* create a new splitter with proper orientation */
	QSplitter *  new_spl = new QSplitter(old_spl);
	new_spl->setOrientation(orient);

	if (old_spl->widget(0) == vp_loc)
	{ /* the viewport is in first slot, so we have to reorder */
		vp_loc->setParent(new_spl);
		old_spl->addWidget(new_spl);
		old_spl->addWidget(old_spl->widget(0));
	}
	else
	{
		vp_loc->setParent(new_spl);
		old_spl->addWidget(new_spl);
	}
	new_spl->addWidget(vp_loc);
	vp_loc->show();

	/* create a clone of current viewport */
	ETSheetView * duplic = new ETSheetView(
				static_cast<ETSheet *>(vp_loc->scene()),
				new_spl);
	duplic->show();
	duplic->setTransform(vp_loc->transform());

	/* restore aspect ratio for original splitter */
	old_spl->setSizes(sz_l);

	/* let the two viewports use equal ammounts of space */
	sz_l.clear();
	sz_l.append(1);
	sz_l.append(1);
	new_spl->setSizes(sz_l);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::splitH          ( void )
{
	QWidget * parent = parentWidget();
	ETSheet * sht = static_cast<ETSheet * >(scene());
	if (parent == sht->assocMDI())
	{ /* top level */
		ivp_SplitTopL(this, sht->assocMDI(), Qt::Vertical);
	}
	else
	{
		ivp_SplitSplKid(this, parent, Qt::Vertical);
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::splitV          ( void )
{
	QWidget * parent = parentWidget();
	ETSheet * sht = static_cast<ETSheet * >(scene());
	if (parent == sht->assocMDI())
	{ /* top level */
		ivp_SplitTopL(this, sht->assocMDI(), Qt::Horizontal);
	}
	else
	{
		ivp_SplitSplKid(this, parent, Qt::Horizontal);
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::splitTgl        ( void )
{
	QWidget * parent = parentWidget();
	if (parent == this)
	{ /* top level */
		QMessageBox::warning(this, tr("Error"),
							 tr("No split to work with"));
		return;
	}
	QSplitter *  old_spl = static_cast<QSplitter *>(parent);
	if (old_spl->orientation() == Qt::Horizontal)
		old_spl->setOrientation(Qt::Vertical);
	else
		old_spl->setOrientation(Qt::Horizontal);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETSheetView::rejoinVP            ( void )
{
	QWidget * parent = parentWidget();
	ETSheet * sht = static_cast<ETSheet * >(scene());
	if (parent == sht->assocMDI())
	{ /* top level */
		QMessageBox::warning(sht->assocMDI(), tr("Error"),
							 tr("No split to delete"));
		return;
	}
	QSplitter *  old_spl = static_cast<QSplitter *>(parent);
	if (old_spl->parentWidget() == sht->assocMDI())
	{
		sht->vp_DelAll();
	}
	else
	{
		QSplitter *  oldold_spl =
				static_cast<QSplitter *>
				(old_spl->parentWidget());
		QList<int> sz_l = old_spl->sizes();
		bool need_shift = (oldold_spl->widget(0) == old_spl);
		setParent(oldold_spl);
		old_spl->close();
		old_spl->deleteLater();
		oldold_spl->addWidget(this);
		if (need_shift)
		{
			oldold_spl->addWidget(oldold_spl->widget(0));
		}
		show();
		oldold_spl->setSizes(sz_l);
		sht->setCurrentVp(this);
	}
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void				ETSheetView::vp_SplitKids			(const QWidget * parent, SplitData * sd)
{

	const QObjectList list = parent->children();
	sd->first.comp.vp = NULL;
	sd->sec.comp.vp = NULL;
	bool b_1 = false;
	foreach (const QObject * l_it, list)
	{
		if (l_it->isWidgetType())
		{
			const QGraphicsView * l_it_v = qobject_cast<const QGraphicsView *>(l_it);
			const QSplitter * l_it_s = qobject_cast<const QSplitter *>(l_it);
			if (b_1)
			{
				if (l_it_v != NULL)
				{
					sd->sec.comp.vp = static_cast<const ETSheetView *>(l_it_v);
					sd->sec.b_is_vp = true;
					return;
				}
				else if (l_it_s != NULL)
				{
					sd->sec.comp.split = l_it_s;
					sd->sec.b_is_vp = false;
					return;
				}
			}
			else
			{
				if (l_it_v != NULL)
				{
					sd->first.comp.vp = static_cast<const ETSheetView *>(l_it_v);
					sd->first.b_is_vp = true;
					b_1 = true;
				}
				else if (l_it_s != NULL)
				{
					sd->first.comp.split = l_it_s;
					sd->first.b_is_vp = false;
					b_1 = true;
				}
			}
		}
	}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETSheetView::setScene ( QGraphicsScene * scene )
{

	ETSheet * sht = static_cast<ETSheet * >(scene);
	if (scene != NULL)
	{

		setBackgroundBrush(QBrush(sht->background()));
	}
	QGraphicsView::setScene(scene);
	setAlignment(Qt::AlignCenter);

	DDHC_REPARENT(sht);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETSheetView::zoomWin		( QPointF pt_1, QPointF pt_2 )
{
	ETSheet * scn = static_cast<ETSheet *>(scene());
	QRectF new_vr(pt_1, pt_2);

	/* create an rectangle that fits current aspect ratio */
	qreal aspect_r = (qreal) width() / (qreal) height();
	qreal conv_w = new_vr.height() * aspect_r;
	if (conv_w > new_vr.width())
	{
		/* center the rectangle on requested rectangle */
		new_vr.setX(
					new_vr.x() - (
						(conv_w - new_vr.width()) / 2
						)
					);
		new_vr.setWidth(conv_w);
	}
	else
	{
		/* compute the new height and store it*/
		conv_w = new_vr.width() / aspect_r;
		/* center the rectangle on requested rectangle */
		new_vr.setX(
					new_vr.y() - (
						(conv_w - new_vr.height()) / 2
						)
					);
		new_vr.setHeight(conv_w);
	}


	/* if the sceneis rotated cancel that */
	if (rot_ang_to_s != 0)
	{
		rotateRight(-rot_ang_to_s);
	}


	/* at this point we could use QGraphicsView::fitInView, but that
	  would trash the scale_to_s, trans_x, trans_y */

	ViewportAnchor 	va = transformationAnchor ();
	setTransformationAnchor(QGraphicsView::NoAnchor);

	/* translate to new position */
	translate(new_vr.topLeft());

	/* scale the thing */
	zoomFactor(new_vr.width() / (width()*scale_to_s));


	setTransformationAnchor(va);

}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void				ETSheetView::zoomExt		( void )
{
	ETSheet * scn = static_cast<ETSheet *>(scene());
	QRectF sr = scn->sceneRect();
	if ((sr.width() < 0.001) || (sr.height() < 0.001))
	{
		return;
	}
	zoomWin(sr.topLeft(), sr.bottomRight());
}
/* ========================================================================= */


/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
